package com.pantuo.sys.service.impl;

import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.pantuo.common.exception.ServiceException;
import com.pantuo.common.utils.DataTablePage;
import com.pantuo.common.utils.TableRequest;
import com.pantuo.sys.bo.StatisticsThreeBo;
import com.pantuo.sys.bo.StatisticsTwoBo;
import com.pantuo.sys.dao.StatisticsOneDao;
import com.pantuo.sys.dao.StatisticsThreeDao;
import com.pantuo.sys.dao.StatisticsTwoDao;
import com.pantuo.sys.pojo.StatisticsOne;
import com.pantuo.sys.pojo.StatisticsThree;
import com.pantuo.sys.pojo.StatisticsTwo;
import com.pantuo.sys.service.StatisticsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;
import sun.java2d.pipe.SpanShapeRenderer;

import java.sql.*;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.*;

@Service
public class StatisticsServiceImpl implements StatisticsService {

    @Autowired
    private StatisticsOneDao statisticsOneDao;

    @Autowired
    private StatisticsTwoDao statisticsTwoDao;

    @Autowired
    private StatisticsThreeDao statisticsThreeDao;

    //用来存放当天最早刷卡记录的id
    private Map<String, String> minIdMap = new HashMap<>();
    //用来存放当天统计那一刻最大的刷卡记录id
    private Map<String, String> maxIdMap = new HashMap<>();

    // 每隔5秒执行一次
    //  0 */1 * * * ?
    /*0,30 1-23 * * *
    分/时/日/月/周*/
    //@Scheduled(cron = "0/3 * 5-23 * * * ")每天早上5点到晚上11点每隔3秒执行一次
    //@Scheduled(cron = "0/5 * 15-16 * * * ")
    //@Scheduled(cron = "0/3 * 5-23 * * * ")
    //@Scheduled(cron = "0/3 * 8,9 * * * ")
    public void printSay() {
        System.out.println("执行啦");
    }

    //date -s "2021-04-22 11:03:00" 21 14
    //@Scheduled(cron = "0/3 * 5-22 * * * ")
    //@Scheduled(cron = "0/3 * 10-10 * * * ")

    //@Scheduled(cron = "* * 23-23 * * ? ")
    public void clearMap() {
        minIdMap.clear();
    }




    //@Scheduled(cron = "0/3 * 5-23 * * * ")
    @Override
    public void findTotal(String date_s) {
        //执行之前先清掉mindIdMap
        clearMap();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        String now = sdf.format(new Date());
        if (now.equals(date_s)){
            return;
        }
        String url = "jdbc:mysql://localhost:3306/oa_data3?serverTimezone=GMT%2B8&characterEncoding=utf8";
        String user = "root";
        String password = "pantuo1709";
        //存放当天各类型的记录数及他们的总和
        Map<String, Integer> map1 = null;
        //存放当天每条线路的各类型的记录数及他们的总和
        Map<StatisticsTwoBo, Integer> map2 = null;
        //存放当天每辆车的各类型的记录数及他们的总和
        Map<StatisticsThreeBo, Integer> map3 = null;
        //当天的日期
        String currentDate = null;
        long start = 0L;
        Connection conn = null;
        PreparedStatement statement = null;
        ResultSet resultSet = null;
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
            conn = DriverManager.getConnection(url, user, password);
            start = System.currentTimeMillis();
            //SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
            //currentDate = sdf.format(new Date());
            //57 26 31
            currentDate = date_s;//"2021-07-19";
            System.out.println(currentDate);
            //currentDate = "2021-04-23";
            //用来存放当天最早刷卡记录的id
            //Map<String, String> minIdMap = new HashMap<>();
            //如果map集合中没有当天最早刷卡记录的id则先查询数据库得到该id
            if (!minIdMap.containsKey("minId")) {
                String findMinId = "select min(id) minId from tn_sfzlog where created_dt like '" + currentDate + "%' ";
                String findMaxId = "select max(id) maxId from tn_sfzlog where created_dt like '" + currentDate + "%' ";
                PreparedStatement preparedStatement1 = conn.prepareStatement(findMinId);
                ResultSet result1 = preparedStatement1.executeQuery();
                PreparedStatement preparedStatement2 = conn.prepareStatement(findMaxId);
                ResultSet result2 = preparedStatement2.executeQuery();
                while (result1.next()) {
                    String mindId = result1.getString("minId");
                    if (mindId != null) {
                        minIdMap.put("minId", mindId);
                    }
                }
                while (result2.next()) {
                    String maxId = result2.getString("maxId");
                    if (maxId != null) {
                        maxIdMap.put("maxId", maxId);
                    }
                }
            }
            System.out.println("min:"+minIdMap.get("minId"));
            System.out.println("max:"+maxIdMap.get("maxId"));
            //查出需要统计的维度
            String sql = "select id,companyName_s, lineName_s, created_dt, r_s, vehicleNum1_s, vehicleNum2_s, devVersion_s from tn_sfzlog where id >= " + minIdMap.get("minId") + " and id <= " + maxIdMap.get("maxId") + " and lineName_s is not null";
            statement = conn.prepareStatement(sql);
            //关键：做一下设置会采用流数据接收方式，每次从服务器接收部分数据，直到所有数据处理完毕，不会发生JVM OOM
            statement.setFetchSize(Integer.MIN_VALUE);
            resultSet = statement.executeQuery();
            map1 = new HashMap<>();
            map2 = new HashMap<>();
            map3 = new HashMap<>();
            //遍历结果集
            while (resultSet.next()) {

                //取出要做统计的列
                //加上公司：2021-12-01修改
                String companyName_s = resultSet.getString("companyName_s");

                String r_s = resultSet.getString("r_s");
                String lineName_s = resultSet.getString("lineName_s");
                String vehicleNum1_s = resultSet.getString("vehicleNum1_s");
                String vehicleNum2_s = resultSet.getString("vehicleNum2_s");
                String devVersion_s = resultSet.getString("devVersion_s");


                StatisticsTwoBo statisticsTwoBo = new StatisticsTwoBo();
                StatisticsThreeBo statisticsThreeBo = new StatisticsThreeBo();
                if (("5".equals(r_s) && "1".equals(devVersion_s)) || "1".equals(r_s) || "2".equals(r_s) || "3".equals(r_s) || "4".equals(r_s)) {
                    statisticsTwoBo.setR_s(r_s);
                    statisticsThreeBo.setR_s(r_s);
                }

                statisticsTwoBo.setCompanyName_s(companyName_s);
                statisticsTwoBo.setLineName_s(lineName_s);

                statisticsThreeBo.setCompanyName_s(companyName_s);
                statisticsThreeBo.setLineName_s(lineName_s);
                statisticsThreeBo.setVehicleNum1_s(vehicleNum1_s);
                statisticsThreeBo.setVehicleNum2_s(vehicleNum2_s);

                //统计当天各个记录数
                if (("5".equals(r_s) && "1".equals(devVersion_s)) || "1".equals(r_s) || "2".equals(r_s) || "3".equals(r_s) || "4".equals(r_s)) {
                    if (!map1.containsKey(r_s)) {
                        map1.put(r_s, 1);
                    } else {
                        map1.put(r_s, map1.get(r_s) + 1);
                    }
                }
                //统计当天每条线路的各个记录数
                if (!map2.containsKey(statisticsTwoBo)) {
                    map2.put(statisticsTwoBo, 1);
                } else {
                    map2.put(statisticsTwoBo, map2.get(statisticsTwoBo) + 1);
                }
                //统计当天每辆车的各个记录数
                if (!map3.containsKey(statisticsThreeBo)) {
                    map3.put(statisticsThreeBo, 1);
                } else {
                    map3.put(statisticsThreeBo, map3.get(statisticsThreeBo) + 1);
                }
            }
        } catch (ClassNotFoundException | SQLException e) {
            e.printStackTrace();
        } finally {
            if (resultSet != null) {
                try {
                    resultSet.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }
            if (statement != null) {
                try {
                    statement.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }
            if (conn != null) {
                try {
                    conn.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }
        }
        //将各类统计数据保存到中间表
        findAllTypeTotal(map1, currentDate);
        findAllTypeTotalAndLine(map2, currentDate);
        findAllTypeTotalAndVe(map3, currentDate);
        long end = System.currentTimeMillis();
        System.out.println("用时: " + (end - start) + "毫秒");
    }


    //保存当天各类型数据
    public void findAllTypeTotal(Map<String, Integer> map1, String currentDate) {
        StatisticsOne statisticsOne = new StatisticsOne();
        statisticsOne.setDate_s(currentDate);
        Set<String> map1KeySet = map1.keySet();
        int sum = 0;
        for (String key : map1KeySet) {
            Integer total = map1.get(key);
            //老人卡
            if ("1".equals(key)) {
                statisticsOne.setAged_i(total);
            }
            //需购票
            if ("2".equals(key)) {
                statisticsOne.setBuyTicket_i(total);
            }
            //已刷卡
            if ("3".equals(key)) {
                statisticsOne.setSwipedCard_i(total);
            }
            //未识别
            if ("5".equals(key)) {
                statisticsOne.setUnrecognized_i(total);
            }
            //爱心卡
            if ("4".equals(key)) {
                statisticsOne.setLoveCard_i(total);
            }
            //ip更新
            if ("9".equals(key)) {
                statisticsOne.setIpUpdate_i(total);
            }
            //刷卡的总数量 = 老人卡 + 需购票 + 未识别 + 爱心卡(ip更新不加)
            if (!"9".equals(key)) {
                sum += total;
                statisticsOne.setAll_i(sum);
            }
        }
        //更新构造器
        UpdateWrapper updateWrapper = new UpdateWrapper();
        updateWrapper.eq("date_s", currentDate);
        //首先根据当天的日期到数据库更新今天的数据
        int rows = statisticsOneDao.update(statisticsOne, updateWrapper);
        //如果rows(受影响的行数)为0说明表中无当天数据，则执行保存操作
        if (rows == 0) {
            statisticsOneDao.insert(statisticsOne);
        }
    }

    //保存当天每条线路的各类型数据
    public void findAllTypeTotalAndLine(Map<StatisticsTwoBo, Integer> map2, String currentDate) {
        Set<StatisticsTwoBo> map2KeySet = map2.keySet();
        Map<String, StatisticsTwo> map = new HashMap<>();
        StatisticsTwo statisticsTwo = null;
        for (StatisticsTwoBo statisticsTwoBo : map2KeySet) {
            String lineName_s = statisticsTwoBo.getLineName_s();
            String companyName_s = statisticsTwoBo.getCompanyName_s();
            String r_s = statisticsTwoBo.getR_s();
            Integer total = map2.get(statisticsTwoBo);
            StatisticsTwoBo twoBo = new StatisticsTwoBo();
            twoBo.setCompanyName_s(companyName_s);
            twoBo.setLineName_s(lineName_s);
            twoBo.setR_s(r_s);
            twoBo.setTotal(map2.get(statisticsTwoBo));
            if (!map.containsKey(twoBo.getLineName_s())) {
                map.put(lineName_s, new StatisticsTwo());
            }
            statisticsTwo = map.get(lineName_s);
            statisticsTwo.putValue(twoBo, currentDate);
        }
        Collection<StatisticsTwo> values = map.values();
        statisticsTwoDao.insertAndUpdate(values);
    }

    //保存当天每辆车的各类型数据
    public void findAllTypeTotalAndVe(Map<StatisticsThreeBo, Integer> map3, String currentDate) {
        Set<StatisticsThreeBo> map3KeySet = map3.keySet();
        Map<String, StatisticsThree> map = new HashMap<>();
        StatisticsThree statisticsThree = null;
        for (StatisticsThreeBo statisticsThreeBo : map3KeySet) {
            String lineName_s = statisticsThreeBo.getLineName_s();
            String vehicleNum1_s = statisticsThreeBo.getVehicleNum1_s();
            String vehicleNum2_s = statisticsThreeBo.getVehicleNum2_s();
            String companyName_s = statisticsThreeBo.getCompanyName_s();
            String r_s = statisticsThreeBo.getR_s();
            StatisticsThreeBo threeBo = new StatisticsThreeBo();
            threeBo.setLineName_s(lineName_s);
            threeBo.setVehicleNum1_s(vehicleNum1_s);
            threeBo.setVehicleNum2_s(vehicleNum2_s);
            threeBo.setR_s(r_s);
            threeBo.setTotal(map3.get(statisticsThreeBo));
            threeBo.setCompanyName_s(companyName_s);
            if (!map.containsKey(threeBo.getVehicleNum2_s())) {
                map.put(vehicleNum2_s, new StatisticsThree());
            }
            statisticsThree = map.get(vehicleNum2_s);
            statisticsThree.putValue(threeBo, currentDate);
        }
        Collection<StatisticsThree> values = map.values();
        statisticsThreeDao.insertAndUpdate(values);
    }


    //将车辆信息缓存到map
    Map<String, Object> cacheMap = new HashMap<>();
    @Override
    public PageImpl<Object> findAllFields(TableRequest request) {
        int start = request.getStart();
        int length = request.getLength();
        Map<String, String> filter = request.getFilter();
        List<Map<String, String>> orderList = request.getOrder();
        List<Map<String, Object>> commonRecords = null;
        Long total = null;
        if (orderList == null) {
            if (cacheMap.containsKey("total")){
                total = (Long) cacheMap.get("total");
            }else {
                total = statisticsOneDao.getTotal(filter);
                cacheMap.put("total", total);
            }
            if (total == 0L) {
                throw new ServiceException("暂无记录");
            } else {
                if(cacheMap.containsKey("allBusInfo")){
                    commonRecords = (List<Map<String, Object>>) cacheMap.get("allBusInfo");
                    return new DataTablePage(new PageImpl(commonRecords, PageRequest.of(start, length), total));
                }else {
                    commonRecords = statisticsOneDao.findAllFields(filter, (Map)null, start, length);
                    cacheMap.put("allBusInfo", commonRecords);
                    return new DataTablePage(new PageImpl(commonRecords, PageRequest.of(start, length), total));
                }
            }
        } else {
            Map<String, String> orderMap = (Map)orderList.get(0);
            total = statisticsOneDao.getTotal(filter);
            if (total == 0L) {
                throw new ServiceException("暂无记录");
            } else {
                commonRecords = statisticsOneDao.findAllFields(filter, orderMap, start, length);
                return new DataTablePage(new PageImpl(commonRecords, PageRequest.of(start, length), total));
            }
        }
    }
}
